﻿
using System.Collections.Generic;
using System.Linq;
using CatEars.Core.Collections;

namespace CatEars.Text.FastFind
{
    /// <summary>
    /// 开始 包含 结尾 三类关键字合并的FastFindSubStr
    /// </summary>
    public class FastFindSubStrEx
    {
        /// <summary>
        /// 空值对象
        /// </summary>
        static readonly SingleLinkedNode<object> m_emptyObjectNode = new SingleLinkedNode<object>();

        /// <summary>
        /// 开始
        /// </summary>
        public FastFindSubStr FastFindStart { get; private set; }
        /// <summary>
        /// 结束
        /// </summary>
        public FastFindSubStr FastFindEnd { get; private set; }
        /// <summary>
        /// 包含
        /// </summary>
        public FastFindSubStr FastFindContain { get; private set; }
        /// <summary>
        /// 完全相同
        /// </summary>
        Dictionary<string, SingleLinkedNode<object>> _equalWords;

        /// <summary>
        /// FastFindSubStrResult中Tag的取值方式
        /// </summary>
        public FastFindResultTagMode TagMode { get; private set; }

        /// <summary>
        /// 初始化
        /// </summary>
        /// <param name="intDepth">索引深度</param>
        /// <param name="tMode">FastFindSubStrResult中Tag的取值方式</param>
        /// <param name="intSubCapacity">内部容器预置容量</param>
        public FastFindSubStrEx(
            int intDepth = 2,
            FastFindResultTagMode tMode = FastFindResultTagMode.Many,
            int intSubCapacity = 0)
        {
            TagMode = tMode;
            _equalWords = new Dictionary<string, SingleLinkedNode<object>>();
            FastFindStart = new FastFindSubStr(intDepth, FastFindIndexMode.Asc, tMode, FastFindResultIndexMode.Start, intSubCapacity);
            FastFindContain = new FastFindSubStr(intDepth, FastFindIndexMode.Asc, tMode, FastFindResultIndexMode.Start, intSubCapacity);
            FastFindEnd = new FastFindSubStr(intDepth, FastFindIndexMode.Desc, tMode, FastFindResultIndexMode.Start, intSubCapacity);
        }

        #region 添加
        /// <summary>
        /// 添加快速搜索子串(包含)
        /// </summary>
        /// <param name="strValue">值</param>
        /// <param name="objTag">附加对象</param>
        public void AddContain(string strValue, object objTag = null)
        {
            FastFindContain.AddValue(strValue, objTag);
        }

        /// <summary>
        /// 添加快速搜索子串(只能在开头)
        /// </summary>
        /// <param name="strValue">值</param>
        /// <param name="objTag">附加对象</param>
        public void AddStart(string strValue, object objTag = null)
        {
            FastFindStart.AddValue(strValue, objTag);
        }

        /// <summary>
        /// 添加快速搜索子串(只能在结尾)
        /// </summary>
        /// <param name="strValue">值</param>
        /// <param name="objTag">附加对象</param>
        public void AddEnd(string strValue, object objTag = null)
        {
            FastFindEnd.AddValue(strValue, objTag);
        }

        /// <summary>
        /// 添加快速搜索子串(只能在结尾)
        /// </summary>
        /// <param name="strValue">值</param>
        /// <param name="objTag">附加对象</param>
        public void AddEqual(string strValue, object objTag = null)
        {
            if (string.IsNullOrEmpty(strValue)) return;
            if (TagMode == FastFindResultTagMode.None)
            {
                //不需要Tag，直接加入字典即可
                _equalWords[strValue] = m_emptyObjectNode;
                return;
            }
            SingleLinkedNode<object> node;
            if (_equalWords.TryGetValue(strValue, out node))
            {
                var node0 = node;
                do
                {
                    if (node0.Value == objTag)
                    {
                        //排除重复的Tag
                        return;
                    }
                    node0 = node0.Next;
                }
                while (node0 != null);
            }
            _equalWords[strValue] = new SingleLinkedNode<object>()
            {
                Value = objTag,
                Next = node,
            };
        }
        #endregion

        /// <summary>
        /// 搜索被包含的子串
        /// </summary>
        /// <param name="str"></param>
        /// <param name="sortMode"></param>
        /// <returns></returns>
        public ICollection<FastFindSubStrResult> FindContain(string str,
            FastFindResultSortMode sortMode)
        {
            if (string.IsNullOrEmpty(str)) return EmptyArray<FastFindSubStrResult>.Array;
            bool blnSingleResult = (sortMode == FastFindResultSortMode.MaxValueLength
                || sortMode == FastFindResultSortMode.MaxValueLengthEachIndex);
            var sortMode0 = blnSingleResult ? sortMode : FastFindResultSortMode.None;

            List<FastFindSubStrResult> result;
            var r0 = FindEqualFromEqualDict(str);
            if (r0 != null)
            {
                if (blnSingleResult && TagMode != FastFindResultTagMode.Many)
                {
                    return new FastFindSubStrResult[] { r0 };
                }
                result = new List<FastFindSubStrResult>();
                result.Add(r0);
            }
            else
            {
                result = new List<FastFindSubStrResult>();
            }
            result.AddRange(FastFindContain.FindContain(str, sortMode));
            result.AddRange(FastFindStart.FindStartWith(str, sortMode));
            result.AddRange(FastFindEnd.FindEndWith(str, sortMode));
            //同位置同词在 _ffssContain _ffssStart _ffssEnd _equalWords 可能出现 需要合并结果
            var result0 = FastFindSubStr.MergeResult(result, TagMode);
            return FastFindSubStr.SortResult(result0, sortMode);
        }

        /// <summary>
        /// 搜索相同项
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public FastFindSubStrResult FindEqual(string str)
        {
            if (string.IsNullOrEmpty(str)) return null;
            FastFindSubStrResult result = null;
            if (TagMode != FastFindResultTagMode.Many)
            {
                result = FindEqualFromEqualDict(str);
                if (result != null) return result;
                result = FastFindContain.FindEqual(str);
                if (result != null) return result;
                result = FastFindStart.FindEqual(str);
                if (result != null) return result;
                result = FastFindEnd.FindEqual(str);
                return result;
            }
            FastFindSubStrResult[] rTmp = new FastFindSubStrResult[4];
            rTmp[0] = FindEqualFromEqualDict(str);
            rTmp[1] = FastFindContain.FindEqual(str);
            rTmp[2] = FastFindStart.FindEqual(str);
            rTmp[3] = FastFindEnd.FindEqual(str);
            return FastFindSubStr.MergeResultToOne(rTmp, TagMode);
        }

        /// <summary>
        /// 在AddEqual中搜索相同项
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public FastFindSubStrResult FindEqualFromEqualDict(string str)
        {
            if (string.IsNullOrEmpty(str)) return null;
            SingleLinkedNode<object> node;
            if (!_equalWords.TryGetValue(str, out node))
            {
                return null;
            }
            if (TagMode == FastFindResultTagMode.None)
            {
                return new FastFindSubStrResult(str, EmptyArray.ObjectArray, 0);
            }
            else if (TagMode == FastFindResultTagMode.Single)
            {
                return new FastFindSubStrResult(str, new object[] { node.Value }, 0);
            }
            else
            {
                HashSet<object> tags = new HashSet<object>();
                do
                {
                    tags.Add(node.Value);
                    node = node.Next;
                }
                while (node != null);
                return new FastFindSubStrResult(str, tags.ToArray(), 0);
            }
        }
    }
}
